<template>
    <div class="three-container">
        <div ref="stage"></div>
    </div>
</template>

<script>
import * as THREE from 'three';
// import OrbitControls from 'three/examples/js/controls/OrbitControls';
import OrbitControls from '../controls/OrbitControls.js';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'

export default {
    name: '',
    components: {
    },
    props: {},
    // 监控data中的数据变化
    watch: {},
    // 定义属性
    data () {
        return {
            container: null, // 渲染的元素根节点
            scene: null, // 场景
            camera: null, // 相机
            renderer: null, // 渲染函数
            // plane: null // 底部的平面
            cube: null,
            animationMixer: null, // 场景中特定对象的动画的播放器
            clock: new THREE.Clock(),
            raycaster: new THREE.Raycaster(),
            mouse: null,
            soldier: null,
            positionSoldier: {
                x: 0.5,
                y: 0.5
            },
            animationClipNow: null
        };
    },
    // 计算属性，会监听依赖属性值随之变化
    computed: {
    },
    // 方法集合
    methods: {
        init () {
            this.scene = new THREE.Scene();
            this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
            this.renderer = new THREE.WebGLRenderer({ antialias: true });
            this.renderer.setSize(window.innerWidth, window.innerHeight);
            this.container = this.$refs.stage;
            this.container.appendChild(this.renderer.domElement);

            window.addEventListener('resize', this.onWindowResize);

            let box1 = {
                width: {
                    x: 1,
                    y: 1,
                    z: 1
                },
                color: 0xff0000,
                position: {
                    x: 10,
                    y: 0,
                    z: 1
                },
                texture: 'http://renyuan.bos.xyz/FloorsCheckerboard_S_Diffuse.jpg',
                name: 'box1'
            };
            this.addBox(box1);
            this.add3dModel('soldier');
            // this.positionSoldier = {
            //     x: 0.5,
            //     y: 0.5
            // };
            // console.log(this.soldier);
            this.setPlane();
            this.addAmbientLight();
            let controls = new OrbitControls(this.camera, this.renderer.domElement);
            controls.update();
            this.camera.position.z = 5;
            // console.log('this.scene:', this.scene);
            // console.log(this.renderer.domElement);
            // 给场景添加监听点击事件
            this.renderer.domElement.addEventListener('click', event => {
                // console.log(event);
                const { offsetX, offsetY } = event;
                // 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)
                const x = (offsetX / window.innerWidth) * 2 - 1;
                const y = - (offsetY / window.innerHeight) * 2 + 1;

                let mouse = new THREE.Vector2(x, y);
                // 通过摄像机和鼠标位置更新射线
                this.raycaster.setFromCamera(mouse, this.camera);
                let intersects = this.raycaster.intersectObjects(this.scene.children, true);
                // let intersect3D = intersects.filter(intersect => !(intersect.object instanceof THREE.GridHelper) && intersect.object.name !== 'plane');
                // console.log(intersect3D);
                // let intersectPlane = intersects.filter(intersect => intersect.object.name === 'plane');
                // console.log(intersectPlane);
                let intersect3D = [];
                let intersectPlane = [];
                intersects.forEach(intersect => {
                    if (intersect.object.name === 'plane') intersectPlane.push(intersect);
                    if (!(intersect.object instanceof THREE.GridHelper) && intersect.object.name !== 'plane') intersect3D.push(intersect);
                });
                // console.log('3d:', intersect3D);
                // console.log('plane:', intersectPlane);
                // console.log(this.soldier);
                this.soldier.scene.translateX((intersectPlane[0].uv.x - this.positionSoldier.x) * 50)
                this.soldier.scene.translateZ(-(intersectPlane[0].uv.y - this.positionSoldier.y) * 50)
                this.positionSoldier = {
                    x: intersectPlane[0].uv.x,
                    y: intersectPlane[0].uv.y
                }
                this.animationMixer.uncacheClip(this.animationClipNow);
                this.animationClipNow = this.soldier.animations.find(item => item.name === 'Idle');
                let action = this.animationMixer.clipAction(this.animationClipNow);
                action.play();
            }, false);

            this.render();
        },
        render () {
            requestAnimationFrame(this.render);
            const box = this.scene.getObjectByName('box1');
            box.rotation.x += 0.01;

            if (this.animationMixer) this.animationMixer.update(this.clock.getDelta());
            this.renderer.render(this.scene, this.camera);
        },
        onWindowResize () {
            // console.log('onWindowResize');
            this.renderer.setSize(window.innerWidth, window.innerHeight);
        },
        setPlane () {
            let planeBufferGeometry = new THREE.PlaneBufferGeometry(50, 50);
            let planMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff, side: THREE.DoubleSide });
            let plane = new THREE.Mesh(planeBufferGeometry, planMaterial);
            plane.name = 'plane';
            plane.rotation.x = -Math.PI / 2;
            this.scene.add(plane);
            let gridHelper = new THREE.GridHelper(50, 50);
            // gridHelper.rotation.x = Math.PI / 2;
            this.scene.add(gridHelper);
        },
        addBox (obj = {}) {
            let texture = obj.texture ? new THREE.TextureLoader().load(obj.texture) : null;
            let boxGeometry = new THREE.BoxGeometry(obj.width.x || 1, obj.width.y || 1, obj.width.z || 1);
            let boxMaterial = new THREE.MeshBasicMaterial({ color: texture ? 0xffffff : obj.color ? obj.color : 0xffffff, map: texture });
            let cube = new THREE.Mesh(boxGeometry, boxMaterial);
            cube.name = obj.name;
            cube.position.set(obj.position.x || 0, obj.position.y || 0, obj.position.z || 0);
            console.log(cube);
            this.scene.add(cube);
        },
        add3dModel (name) {
            if (!this.animationMixer) this.animationMixer = new THREE.AnimationMixer(this.scene);
            let loader = new GLTFLoader();
            loader.load(`/models/${name}.glb`, obj => {
                console.log(obj);
                obj.scene.name = name;
                // obj.scene.translateX(5);
                this.scene.add(obj.scene);
                // obj.position.x = 10;
                // obj.position.z = 1;
                // let animationClipIdle = obj.animations.find(item => item.name === 'idle');
                this.animationClipNow = obj.animations.find(item => item.name === 'Run');
                let action = this.animationMixer.clipAction(this.animationClipNow);
                action.play();
                // console.log(obj.scene);
                // return obj.scene;
                this[name] = obj;
            });
        },
        // 为场景添加环境光
        addAmbientLight () {
            let light = new THREE.AmbientLight(0xffffff, 1); // soft white light
            this.scene.add(light);
        }
    },
    // 生命周期 - 创建完成（可以访问当前this实例）
    created () {
    },
    beforeMount () {
    },
    // 生命周期 - 挂载完成（可以访问DOM元素）
    mounted () {
        this.init();
    }
};
</script>

<style lang='less' scoped>
</style>
